/*
 * SipServer.h
 *
 *  Created on: 2016年9月20日
 *      Author: zhengboyuan
 */

#ifndef SIPSERVER_H_
#define SIPSERVER_H_

#include "Resip.h"

#include "AppConfig.h"

#include "resip/stack/EventStackThread.hxx"

#include "resip/dum/DumShutdownHandler.hxx"
#include "resip/dum/RegistrationHandler.hxx"
#include "resip/dum/InviteSessionHandler.hxx"
#include "resip/dum/ClientPagerMessage.hxx"
#include "resip/dum/ServerPagerMessage.hxx"
#include "resip/dum/PagerMessageHandler.hxx"
#include "resip/dum/OutOfDialogHandler.hxx"

#include "resip/dum/ClientSubscription.hxx"
#include "resip/dum/ServerSubscription.hxx"
#include "resip/dum/ClientPublication.hxx"
#include "resip/dum/ServerPublication.hxx"
#include "resip/dum/SubscriptionHandler.hxx"
#include "resip/dum/ExternalMessageHandler.hxx"

#include "HttpServer.h"

#include "RtpMedium.h"

#include "UserAppDialog.h"
#include "UserAppDialogSetFactory.h"
#include "CRegUserStore.h"
#include "MediaSystem.h"
#include "MediaSessionMap.h"
#include "Socket.h"


typedef resip::SharedPtr< resip::UserProfile >      UserProfilePtr;

using namespace resip;



class SipServer : public ThreadIf
				, public DumShutdownHandler
				, public ClientRegistrationHandler
				, public ServerRegistrationHandler
				, public InviteSessionHandler
				, public ClientPagerMessageHandler
				, public ServerPagerMessageHandler
				, public OutOfDialogHandler
				//, public ClientSubscriptionHandler
				, public ServerSubscriptionHandler
				, public ExternalMessageHandler
				, public HttpHandler
				, public av::MediaSystemSink
{
public:
	SipServer();
	virtual ~SipServer();

	bool start();
	void stop();

	void test();

	AppConfig& config();

	void onApplicationTimer(unsigned int timerId, unsigned int durationMs, unsigned int seqNumber, const Data& name);

	int getLocalPort();

	void setHttpServer(HttpServer* server);


protected:
	void setupData();
	std::string getDeviceConfigPath();

	std::string getMediaAddr();
	std::string getHostAddr();

	void registerProxy();
	void unregisterProxy();

	NameAddr makeAddrFromAudioUri(const std::string& audio);

	std::string makeUserAnswer(UserAppDialog* userDialog);
	std::string makeAudioDevOffer(const NameAddr& addr, const std::string& ip, uint16_t port);

	void tryCloseSession(MediaSessionPtr& mediaSession);
	void closeSession(MediaSessionPtr& mediaSession);

	bool handleUserSdp(UserAppDialog* userDialog, InviteSessionHandle handle, const SdpContents& contents);
	bool handleUserOffer(UserAppDialog* userDialog, InviteSessionHandle handle, const SdpContents& contents);
	bool handleUserAnswer(UserAppDialog* userDialog, InviteSessionHandle handle, const SdpContents& contents);

	void handleMediaFormatReady(MediaSessionPtr& mediaSession, av::MediaFormat& fmt);
	void handleMediaReady(MediaSessionPtr& mediaSession);
	void handleMediaReady(MediaSessionPtr& mediaSession, ServerInviteSessionHandle handle);


protected:
	MediaSessionMap		m_mediaSessionMap;

	av::MediaSystemPtr  m_mediaSystem;

protected:
	void setupMasterProfile();

	void setupDum();
	void teardown();

	Uri getContact(ClientRegistrationHandle& handle);
	Uri getContact(ServerRegistrationHandle& handle);

	void acceptInvite(InviteSessionHandle& handle);
	void acceptInvite(ServerInviteSessionHandle& handle);

	bool findVideoMedium(const SdpContents& contents, RtpMedium& rtpMedium);
	bool findH264Medium(const SdpContents& contents, RtpMedium& rtpMedium);

	void rejectInvite(InviteSessionHandle& handle, int code);
	void rejectInvite(ClientInviteSessionHandle& handle, int code);
	void rejectInvite(ServerInviteSessionHandle& handle, int code);
	void rejectInvite(InviteSessionHandle& handle, int code, const char* reason);
	void rejectInvite(ServerInviteSessionHandle& handle, int code, const char* reason);

	void startApplicationTimer(unsigned int timerId, unsigned int durationMs, unsigned int seqNumber, const Data& name);
	void post(ApplicationMessage& message, unsigned int ms);

	void checkServerRegistrationExpire();

	bool getDeviceID(const Data& num, Data& deviceID);

protected:
	SipStack    m_stack;

	SharedPtr<FdPollGrp> m_pollGroup;
	SharedPtr<EventThreadInterruptor> m_interruptor;
	SharedPtr<EventStackThread> m_stackThread;

	SharedPtr<DialogUsageManager> m_dum;
	SharedPtr<MasterProfile> m_profile;

	SharedPtr<RegistrationPersistenceManager> m_regManager;
	SharedPtr<ServerAuthManager>    m_authManager;

	bool    m_shuttingDown;
	ClientRegistrationHandle m_regHandle;
	unsigned int m_regRetryDelayTime;


	AppConfig 	m_config;
	CRegUserStore m_userStore;

	HttpServer*	m_httpServer;


protected:
	virtual int handleJsonApi(const mg_str& method, const mg_str& uri,
				const mg_str& query, const mg_str& body,
				std::string& json);

	virtual void handleUpload(const char* name, const std::string& filepath);

	virtual int handleFileApi(const mg_str& method, const mg_str& uri,
			const mg_str& query, const mg_str& body,
			std::string& resp, std::string& mime);

	virtual void handleWebSocketFrame(unsigned char *data, size_t size, unsigned char flags);


	virtual void onDeviceStatus(const av::MediaSystem::Device& device);


protected:
	virtual void thread();

	virtual void onDumCanBeDeleted();

	/// server reg
	/// Called when registration is refreshed
	virtual void onRefresh(ServerRegistrationHandle, const SipMessage& reg);
	/// called when one or more specified contacts is removed
	virtual void onRemove(ServerRegistrationHandle, const SipMessage& reg);
	/// Called when all the contacts are removed using "Contact: *"
	virtual void onRemoveAll(ServerRegistrationHandle, const SipMessage& reg);
	/** Called when one or more contacts are added. This is after
	authentication has all succeeded */
	virtual void onAdd(ServerRegistrationHandle handle, const SipMessage& reg);
	/// Called when a client queries for the list of current registrations
	virtual void onQuery(ServerRegistrationHandle, const SipMessage& reg);


	/// Called when registraion succeeds or each time it is sucessfully
	/// refreshed (manual refreshes only).
	virtual void onSuccess(ClientRegistrationHandle, const SipMessage& response);

	// Called when all of my bindings have been removed
	virtual void onRemoved(ClientRegistrationHandle, const SipMessage& response);

	/// call on Retry-After failure.
	/// return values: -1 = fail, 0 = retry immediately, N = retry in N seconds
	virtual int onRequestRetry(ClientRegistrationHandle, int retrySeconds, const SipMessage& response);

	/// Called if registration fails, usage will be destroyed (unless a
	/// Registration retry interval is enabled in the Profile)
	virtual void onFailure(ClientRegistrationHandle, const SipMessage& response);

	/// Called when a TCP or TLS flow to the server has terminated.  This can be caused by socket
	/// errors, or missing CRLF keep alives pong responses from the server.
	//  Called only if clientOutbound is enabled on the UserProfile and the first hop server
	/// supports RFC5626 (outbound).
	/// Default implementation is to immediately re-Register in an attempt to form a new flow.
	virtual void onFlowTerminated(ClientRegistrationHandle);


	// invite handler
	/// called when an initial INVITE or the intial response to an outoing invite
	virtual void onNewSession(ClientInviteSessionHandle, InviteSession::OfferAnswerType oat, const SipMessage& msg);
	virtual void onNewSession(ServerInviteSessionHandle, InviteSession::OfferAnswerType oat, const SipMessage& msg);

	/// Received a failure response from UAS
	virtual void onFailure(ClientInviteSessionHandle, const SipMessage& msg);

	/// called when an in-dialog provisional response is received that contains a body
	virtual void onEarlyMedia(ClientInviteSessionHandle, const SipMessage&, const SdpContents&);
	virtual void onEarlyMedia(ClientInviteSessionHandle, const SipMessage&, const Contents&);

	/// called when dialog enters the Early state - typically after getting 18x
	virtual void onProvisional(ClientInviteSessionHandle, const SipMessage&);

	/// called when a dialog initiated as a UAC enters the connected state
	virtual void onConnected(ClientInviteSessionHandle, const SipMessage& msg);

	/// called when a dialog initiated as a UAS enters the connected state
	virtual void onConnected(InviteSessionHandle, const SipMessage& msg);

	virtual void onTerminated(InviteSessionHandle, InviteSessionHandler::TerminatedReason reason, const SipMessage* related);

	/// called when a fork that was created through a 1xx never receives a 2xx
	/// because another fork answered and this fork was canceled by a proxy.
	virtual void onForkDestroyed(ClientInviteSessionHandle);

	/// called when a 3xx with valid targets is encountered in an early dialog
	/// This is different then getting a 3xx in onTerminated, as another
	/// request will be attempted, so the DialogSet will not be destroyed.
	/// Basically an onTermintated that conveys more information.
	/// checking for 3xx respones in onTerminated will not work as there may
	/// be no valid targets.
	virtual void onRedirected(ClientInviteSessionHandle, const SipMessage& msg);

	/// called when an answer is received - has nothing to do with user
	/// answering the call
	virtual void onAnswer(InviteSessionHandle, const SipMessage& msg, const SdpContents&);
	/// called when an offer is received - must send an answer soon after this
	virtual void onOffer(InviteSessionHandle, const SipMessage& msg, const SdpContents&);
	/// called when an Invite w/out offer is sent, or any other context which
	/// requires an offer from the user
	virtual void onOfferRequired(InviteSessionHandle, const SipMessage& msg);

	/// called if an offer in a UPDATE or re-INVITE was rejected - not real
	/// useful. A SipMessage is provided if one is available
	virtual void onOfferRejected(InviteSessionHandle, const SipMessage* msg);

	/// called when INFO message is received
	/// the application must call acceptNIT() or rejectNIT()
	/// once it is ready for another message.
	virtual void onInfo(InviteSessionHandle, const SipMessage& msg);

	/// called when response to INFO message is received
	virtual void onInfoSuccess(InviteSessionHandle, const SipMessage& msg);
	virtual void onInfoFailure(InviteSessionHandle, const SipMessage& msg);

	/// called when MESSAGE message is received
	virtual void onMessage(InviteSessionHandle, const SipMessage& msg);

	/// called when response to MESSAGE message is received
	virtual void onMessageSuccess(InviteSessionHandle, const SipMessage& msg);
	virtual void onMessageFailure(InviteSessionHandle, const SipMessage& msg);

	/// called when an REFER message is received.  The refer is accepted or
	/// rejected using the server subscription. If the offer is accepted,
	/// DialogUsageManager::makeInviteSessionFromRefer can be used to create an
	/// InviteSession that will send notify messages using the ServerSubscription
	virtual void onRefer(InviteSessionHandle, ServerSubscriptionHandle, const SipMessage& msg);

	virtual void onReferNoSub(InviteSessionHandle, const SipMessage& msg);

	/// called when an REFER message receives a failure response
	virtual void onReferRejected(InviteSessionHandle, const SipMessage& msg);

	/// called when an REFER message receives an accepted response
	virtual void onReferAccepted(InviteSessionHandle, ClientSubscriptionHandle, const SipMessage& msg);


	// Called when a MESSAGE has been successfully sent
	virtual void onSuccess(ClientPagerMessageHandle, const SipMessage& status);
	//!kh!
	// Application could re-page the failed contents or just ingore it.
	virtual void onFailure(ClientPagerMessageHandle, const SipMessage& status, std::auto_ptr<Contents> contents);

	virtual void onMessageArrived(ServerPagerMessageHandle, const SipMessage& message);


	/// client sub
	//Client must call acceptUpdate or rejectUpdate for any onUpdateFoo
	virtual void onUpdatePending(ClientSubscriptionHandle, const SipMessage& notify, bool outOfOrder);
	virtual void onUpdateActive(ClientSubscriptionHandle, const SipMessage& notify, bool outOfOrder);
	//unknown Subscription-State value
	virtual void onUpdateExtension(ClientSubscriptionHandle, const SipMessage& notify, bool outOfOrder);

	virtual int onRequestRetry(ClientSubscriptionHandle, int retrySeconds, const SipMessage& notify);

	//subscription can be ended through a notify or a failure response.
	virtual void onTerminated(ClientSubscriptionHandle, const SipMessage* msg);
	//not sure if this has any value.
	virtual void onNewSubscription(ClientSubscriptionHandle, const SipMessage& notify);

	/// server sub
	virtual void onNewSubscription(ServerSubscriptionHandle, const SipMessage& sub);
	virtual void onTerminated(ServerSubscriptionHandle);


	// Client Handlers
	virtual void onSuccess(ClientOutOfDialogReqHandle, const SipMessage& successResponse);
	virtual void onFailure(ClientOutOfDialogReqHandle, const SipMessage& errorResponse);

	// Server Handlers
	virtual void onReceivedRequest(ServerOutOfDialogReqHandle, const SipMessage& request);

	virtual void onMessage(ExternalMessageBase* externalMessage, bool& handled);


};

#endif /* SIPSERVER_H_ */
